home *** CD-ROM | disk | FTP | other *** search
/ Scene Storm / Scene Storm - Volume 1.iso / coding / c / snoopdos_source / patchcode.s < prev    next >
Text File  |  1996-02-16  |  5KB  |  145 lines

  1. *****************************************************************************
  2. *
  3. *    PATCHCODE.S                        vi:ts=8
  4. *
  5. *    Copyright (c) Eddy Carroll, September 1994.
  6. *
  7. *    Patch code used by SnoopDos 3.0. This is copied into the
  8. *    patch table when we first install the SnoopDos patches.
  9. *
  10. *****************************************************************************
  11.  
  12.     XDEF    _PatchCode_Start
  13.     XDEF    _PatchCode_NormalReturn
  14.     XDEF    _PatchCode_JumpOrigFunc
  15.     XDEF    _PatchCode_End
  16.  
  17.     include "exec/execbase.i"
  18.     include    "exec/tasks.i"
  19.  
  20.     SECTION    Text,CODE
  21.  
  22. ;
  23. ;    This is the entry point for the patch. It checks to see if
  24. ;    the patch is currently enabled or not and if it isn't,
  25. ;    jumps to the original function instead. Normally, if the
  26. ;    patch isn't enabled, we will remove it completely, but if
  27. ;    something has patched it after we did, we can't remove it
  28. ;    so this code is needed.
  29. ;
  30. ;    Note that we do a slight trick to check if the patch is enabled
  31. ;    as quickly as possible. We'd like to say CMPI.W #0,enabled(pc)
  32. ;    or similar, but that won't work on a 68000. So instead, we ensure
  33. ;    that the enabled flag is always either $00000000 or $FFFFFFFF, and
  34. ;    then check A7 (which is guaranteed to never be either value)
  35. ;    against it.
  36. ;
  37. _PatchCode_Start:
  38.  
  39.     cmp.l     enabled(pc),a7        ; Patch enabled?
  40.     blo.b   callnewfunc          ; If so, call new function
  41.     move.l  origfunc(pc),-(a7)    ; Else call old function
  42.     rts                ;        
  43.  
  44. ;----------------------------------------------------------------------------
  45. ;
  46. ;    Calling our new function. We do the following:
  47. ;
  48. ;        - Check that we have enough stack to execute the patch.
  49. ;        - Increment usage count to show someone is running the patch code
  50. ;        - Call the new patch code. If the patch code decides not to monitor
  51. ;          the call, it will adjust the return address on the stack to
  52. ;          return to a different point.
  53. ;        - Decrement usage count, and return to caller
  54. ;
  55. ;    If the stack return address was adjusted, it points to code that:
  56. ;
  57. ;        - Decrements the usage count
  58. ;        - Jumps to the original function
  59. ;
  60. ;    The reason we do it like this is so that when we are ignoring a
  61. ;    particular task, any calls made by the task will return to this
  62. ;    patch code rather than our C code. This allows the C code to be
  63. ;    unloaded even if there are still some calls that have not yet
  64. ;    returned (e.g. a RunCommand() call while booting.)
  65. ;
  66. ;    WARNING: If you make any changes here that will adjust the stack
  67. ;    contents on entry to the C code, you MUST update the MarkCallAddr
  68. ;    and CallAddr macros in PATCHES.C accordingly. Ditto for the
  69. ;    JumpOrigFunc[] macro.
  70. ;
  71. callnewfunc:
  72.  
  73.     movem.l    a0/a1/d1/a5,-(a7)    ; Save registers
  74. ;
  75. ;    Now some stack checking code. If the A7 lies in the range
  76. ;    SPLower to SPUpper for the current task, then we check if
  77. ;    there's enough room left on the stack to carry out the call.
  78. ;
  79. ;    If A7 doesn't seem to be on the task's stack, then it means
  80. ;    the task has allocated a different stack -- it's either a
  81. ;    CLI program or a SAS-compiled program that allocated a new
  82. ;    stack. In either case, we assume the program has allocated
  83. ;    sufficient stack space (the only things that will really cause
  84. ;    a problem are tasks with very small stacks, like device drivers).
  85. ;
  86.     move.l    sysbase(pc),a5        ; Get pointer to this task
  87.     move.l    ThisTask(a5),a5        ;
  88.     cmp.l    TC_SPUPPER(a5),a7    ; Check if A7 above upper stack bound?
  89.     bhi.s    stack_okay        ; If so, no point in checking further
  90.     move.l    TC_SPLOWER(a5),a5    ; Get lower bound
  91.     cmp.l    a5,a7            ; Check if A7 below lower stack bound?
  92.     blo.s    stack_okay        ; If so, no point in checking further
  93.     add.l    stackneeded(pc),a5    ; Calculate space needed
  94.     cmp.l    a5,a7            ; Does A7 remain within bounds?
  95.     blo.s    stack_failed        ; If not, skip this call
  96.  
  97. stack_okay:
  98.     lea.l    usecount(pc),a5        ;
  99.     addq.w    #1,(a5)            ; Increment usage count
  100.     move.l    newfunc(pc),a5        ;
  101.     jsr    (a5)            ; Call the C patch code
  102.  
  103. _PatchCode_NormalReturn:
  104.  
  105.     lea.l    usecount(pc),a5        ; 
  106.     subq.w    #1,(a5)            ; Decrement usage count
  107.     movem.l    (a7)+,a0/a1/d1/a5    ; Restore registers
  108.     move.l    d0,d1            ; Copy D0 to D1 for compatibility
  109.     rts                ; And return to caller
  110. ;
  111. ;    We reach here by patching the return address directly on the stack.
  112. ;    If D0 is one of the parameters to the function, then the return
  113. ;    value from the function must be that parameter, so that D0 will
  114. ;    be setup correctly for calling the real function.
  115. ;
  116. _PatchCode_JumpOrigFunc:
  117.  
  118.     lea.l    usecount(pc),a5        ;
  119.     subq.w    #1,(a5)            ; Decrement usage count 
  120.  
  121. stack_failed:
  122.     movem.l    (a7)+,a0/a1/d1/a5    ; Restore registers
  123.     move.l  origfunc(pc),-(a7)    ; Jump to original function
  124.     rts                ;        
  125.     
  126.     cnop    0,4            ; Keep remainder long word aligned
  127.  
  128. _PatchCode_End:
  129. ;
  130. ;    The following fields are also defined in the C Patch structure.
  131. ;    The two definitions must match exactly or Bad Things will happen.
  132. ;
  133. ;    They follow the above code directly, rather than appearing in a
  134. ;    separate section, because they are accessed using PC-relative
  135. ;    addressing.
  136. ;
  137. origfunc    dc.l    0        ; Pointer to original function
  138. newfunc        dc.l    0        ; Pointer to our replacement code
  139. enabled        dc.l    0        ; True if enabled
  140. sysbase        dc.l    0        ; Points to ExecBase
  141. stackneeded    dc.l    0        ; #bytes free stack required
  142. usecount    dc.w    0        ; Number of callers in function
  143.  
  144.     END
  145.